package com.cslc.wechat.common.dao.impl;


import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.hibernate.transform.Transformers;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.cslc.wechat.common.dao.BaseDAO;

@SuppressWarnings({"unchecked","rawtypes"})
public class BaseDAOImpl extends HibernateDaoSupport implements BaseDAO{
	public BaseDAOImpl() {
		super();
	}

	@Transactional
	public void delete(Object entity) {
		this.getHibernateTemplate().delete(entity);
		
	}

	@Transactional
	public <T> void deleteById(Class<T> entityClass, int id) {
		this.getHibernateTemplate().delete(this.findById(entityClass, id));
	}
	@Transactional
	public <T> void deleteById(Class<T> entityClass, long id) {
		this.getHibernateTemplate().delete(this.findById(entityClass, id));
	}

	public <T> T findById(Class<T> entityClass, int id) {
		return (T) this.getHibernateTemplate().get(entityClass, id);
	}

	public <T> T findById(Class<T> entityClass, long id){
		return (T) this.getHibernateTemplate().get(entityClass, id);
	}
	
	public <T> List<T> findByExample(Object entity) {
		return (List<T>) this.getHibernateTemplate().findByExample(entity);
	}

	@Transactional
	public void save(Object entity) {
		this.getHibernateTemplate().save(entity);
	}

	@Transactional
	public void update(Object entity) {
		this.getHibernateTemplate().update(entity);
	}
	
	@Override
	@Transactional
	public <T> void deleteAllEntities(Collection<T> entities){
		this.getHibernateTemplate().deleteAll(entities);
	}
	
	@Override
	@Transactional
	public <T> void batchInsert(Collection<T> entities){
		this.getHibernateTemplate().saveOrUpdateAll(entities);
		this.getHibernateTemplate().flush();
		for (Iterator iterator = entities.iterator(); iterator.hasNext();) {
			Object object = (Object) iterator.next();
			this.getHibernateTemplate().evict(object);
		}
	}
	
	@Transactional
	public void batchInsertOrUpdate(final Collection entities) {
		this.getHibernateTemplate().saveOrUpdateAll(entities);
		this.getHibernateTemplate().flush();
		for (Iterator iterator = entities.iterator(); iterator.hasNext();) {
			Object object = (Object) iterator.next();
			this.getHibernateTemplate().evict(object);
		}
	}
	
	@Transactional
	public int batchUpdate(final String updateString) {
		return getHibernateTemplate().bulkUpdate(updateString);
	}

	@Transactional
	public int batchUpdate(final String updateString, final Object entity) {
		return getHibernateTemplate().bulkUpdate(updateString, entity);
	}

	@Transactional
	public int batchUpdate(final String updateString, final Object[] entities) {
		return getHibernateTemplate().bulkUpdate(updateString, entities);
	}
	
	/**
	 * 根据Critera条件查询
	 * 
	 * @param criteria
	 * @return 查询结果
	 * @author lifengyong
	 * @version 1.00 新建
	 */
	public List findByCriteria(DetachedCriteria criteria){
		return getHibernateTemplate().findByCriteria(criteria);
	}
	
	/**
	 * 根据构造的综合查询条件查找符合条件的记录的总数
	 * @param detachedCriteria 构造的查询对象
	 * @return 符合查询条件的记录总数
	 * 
	 * @author lifengyong
	 * @version 1.00
	 */
	public int findByCriteriaCounts(DetachedCriteria detachedCriteria){
		detachedCriteria.setProjection(Projections.rowCount());
		List<?> list = findByCriteria(detachedCriteria);
		detachedCriteria.setProjection(null);
		if(CollectionUtils.isEmpty(list)) {
		    return 0;
		}
		
		Long count = (Long)list.get(0);
//		int count = ((Integer)list.get(0)).intValue();
//		清除criteria中的修改，以便于下一次应用
		return count.intValue();
	}
	
	/**
	 * 用于分页查询,根据综合条件查询（可以根据查询条件的构造，查询不同的对象）
	 * 
	 * @param detachedCriteria 构造的查询对象
	 * @param rollPage 分页辅助类
	 * @return 需要查询的对象的集合
	 * 
	 * @author lifengyong
	 * @version 1.00
	 */
	public List findByCriteria(DetachedCriteria detachedCriteria, final int offSet,
			final int pageSize){
		return  getHibernateTemplate().findByCriteria(
				detachedCriteria, offSet, pageSize);
	}
  
    /**
	 * 使用hql语句进行查询
	 * 
	 * @param hql 需要查询的hql语句
	 * @param values 如果hql有多个个参数需要传入，values就是传入hql的参数数组
	 * 
	 * @return 查询出的所有记录
	 */
	public List findByHQL(final String hql, final Object[] values) {
	    // 通过一个HibernateCallback对象来执行查询
	    List list = getHibernateTemplate().executeFind(new HibernateCallback() {
	        // 实现HibernateCallback接口必须实现的方法
	        public Object doInHibernate(Session session)
	            throws HibernateException, SQLException {
	            Query query = session.createQuery(hql);
	            // 为hql语句传入参数
	            if(values != null) {
	           	    for (int i = 0 ; i < values.length ; i++){
		                query.setParameter(i, values[i]);
		            }
	            }
	            List result = query.list();
	            return result;
	        }
	    });
	    return list;
	}
	
	/**
	 * 使用hql语句进行查询
	 * 
	 * @param hql 需要查询的hql语句
	 * @param values 如果hql有多个个参数需要传入，values就是传入hql的参数数组
	 * 
	 * @return 查询出的所有记录
	 */
	public <T> T findByHQLFirst(final String hql, final Object[] values) {
	    // 通过一个HibernateCallback对象来执行查询
	    List list = findByHQL(hql, values);
	    return (T)getFirstElement(list);
	    
	}
	
	public static <T> T getFirstElement(Collection<T> collection) {
    	if(collection == null || collection.isEmpty()) {
    		return null;
    	}
    	return collection.iterator().next();
    }
	
	/**
	 * 使用sql语句进行查询
	 * 
	 * @param sql 需要查询的sql语句
	 * @param values 如果hql有多个个参数需要传入，values就是传入hql的参数数组
	 * 
	 * @return 查询出的所有记录
	 */
	public List findBySQL(final String sql, final Object[] values) {
	    // 通过一个HibernateCallback对象来执行查询
	    List list = getHibernateTemplate().executeFind(new HibernateCallback() {
	        // 实现HibernateCallback接口必须实现的方法
	        public Object doInHibernate(Session session)
	            throws HibernateException, SQLException {
	            Query query = session.createSQLQuery(sql);
	            // 为hql语句传入参数
	            if(values != null) {
	           	    for (int i = 0 ; i < values.length ; i++){
		                query.setParameter(i, values[i]);
		            }
	            }
	            List result = query.list();
	            return result;
	        }
	    });
	    return list;
	}
	
	public <T> List<T> findObjectBySql(final String sql, final Class<T> entityClass, final Object[] values) {
		List list = this.getHibernateTemplate().executeFind(
				new HibernateCallback() {
					// Implement the method required by the interface.
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query query = session.createSQLQuery(sql).
								setResultTransformer(Transformers.aliasToBean(entityClass));
			            // 为hql语句传入参数
			            if(values != null) {
			           	    for (int i = 0 ; i < values.length ; i++){
				                query.setParameter(i, values[i]);
				            }
			            }
			            List result = query.list();
			            return result;
					}
				});
		return (List<T>) list;
	}
	
	public <T> List<T> findObjectByHql(final String hql, final Class<T> entityClass, final Object[] values) {
		List list = this.getHibernateTemplate().executeFind(
				new HibernateCallback() {
					// Implement the method required by the interface.
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query query = session.createQuery(hql).
								setResultTransformer(Transformers.aliasToBean(entityClass));
			            // 为hql语句传入参数
			            if(values != null) {
			           	    for (int i = 0 ; i < values.length ; i++){
				                query.setParameter(i, values[i]);
				            }
			            }
			            List result = query.list();
			            return result;
					}
				});
		return (List<T>) list;
	}
	
	/**
	 * 执行hql语句
	 * 
	 * @param hql 需要执行的hql语句
	 * @param values 如果hql有多个个参数需要传入，values就是传入hql的参数数组
	 * 
	 * @return 执行记录数
	 */
	public int executeByHql(final String hql, final Object[] values) {
	    // 通过一个HibernateCallback对象来执行查询
	    int counts = (Integer)getHibernateTemplate().execute(new HibernateCallback() {
	        // 实现HibernateCallback接口必须实现的方法
	        public Object doInHibernate(Session session)
	            throws HibernateException, SQLException {
	            Query query = session.createQuery(hql);
	            // 为hql语句传入参数
	            if(values != null) {
	           	    for (int i = 0 ; i < values.length ; i++){
		                query.setParameter(i, values[i]);
		            }
	            }
	            return query.executeUpdate();
	        }
	    });
	    
	    return counts;
	}
	
	/**
	 * 执行sql语句
	 * 
	 * @param sql 需要执行的sql语句
	 * @param values 如果sql有多个个参数需要传入，values就是传入sql的参数数组
	 * 
	 * @return 执行记录数
	 */
	public int executeBySql(final String sql, final Object[] values) {
	    // 通过一个HibernateCallback对象来执行查询
	    int counts = (Integer)getHibernateTemplate().execute(new HibernateCallback() {
	        // 实现HibernateCallback接口必须实现的方法
	        public Object doInHibernate(Session session)
	            throws HibernateException, SQLException {
	            Query query = session.createSQLQuery(sql);
	            // 为sql语句传入参数
	            if(values != null) {
	           	    for (int i = 0 ; i < values.length ; i++){
		                query.setParameter(i, values[i]);
		            }
	            }
	            return query.executeUpdate();
	        }
	    });
	    
	    return counts;
	}

	/** 
	 * 查询所有记录数
	 * 
	 * @param hql 查询的语句
	 * @param 参数
	 * 
	 * @return 总记录数
	 */
	public long findCountByHQL(final String hql, final Object[] values) {
		List list  = getHibernateTemplate().executeFind(new HibernateCallback() {
	         public Object doInHibernate(Session session)
	             throws HibernateException, SQLException {
	             Query query = session.createQuery(hql);
	             if(values!=null) {
	            	 for (int i = 0 ; i < values.length ; i++){
		                 query.setParameter(i, values[i]);
		             }
	             }
	             List result = query.list();
	             return result;
	         }
	     });
		
		if(list != null && list.size() > 0) {
			return (Long)(list.get(0));
		} 
		return 0;
	}
	
	/** 
	 * 查询所有记录数
	 * 
	 * @param sql 查询的语句
	 * @param 参数
	 * 
	 * @return 总记录数
	 */
	public long findCountBySQL(final String sql, final Object[] values) {
		List countList  = getHibernateTemplate().executeFind(new HibernateCallback() {
	         public Object doInHibernate(Session session)
	             throws HibernateException, SQLException {
	             Query query = session.createSQLQuery(sql);
	             if(values!=null) {
	            	 for (int i = 0 ; i < values.length ; i++){
		                 query.setParameter(i, values[i]);
		             }
	             }
	             List result = query.list();
	             return result;
	         }
	     });
		
		if(countList != null && countList.size() > 0) {
		    return Long.parseLong(countList.get(0).toString());
		}
		return 0;
	}
	
	/** 
	 * 查询所有记录数
	 * 
	 * @param sql 查询的语句
	 * @param 参数
	 * 
	 * @return 总记录数
	 */
	public int findCountBySQL(final String sql) {
		List countList  = getHibernateTemplate().executeFind(new HibernateCallback() {
	         public Object doInHibernate(Session session)
	             throws HibernateException, SQLException {
	             Query query = session.createSQLQuery(sql);
	             List result = query.list();
	             return result;
	         }
	     });
		
		if(countList != null && countList.size() > 0) {
			BigDecimal big = (BigDecimal)countList.get(0);
		    return big.intValue();
		}
		return 0;
	}		

	public <T> List<T> findAll(Class<T> entityClass) {
		return (List<T>) this.getHibernateTemplate().find(
				"from " + entityClass.getName());
	}

	public <T> List<T> findByProperty(Class<T> entityClass,
			String propertyName, String propertyValue) {
		String queryString = "from " + entityClass.getName()
				+ " as model where model." + propertyName + "= '"
				+ propertyValue + "'";
		return (List<T>) getHibernateTemplate().find(queryString);
	}
	public <T> T findByPropertyFirst(Class<T> entityClass,
			String propertyName, String propertyValue) {
		List list = findByProperty(entityClass, propertyName, propertyValue);
	    return (T)getFirstElement(list);
	}

	public <T> List<T> findByPage(Class<T> entityClass, final int offSet) {
		final String hql = "from " + entityClass.getName()+" where 1 = 1";
		// Do the query using HibernateCallback.
		List list = this.getHibernateTemplate().executeFind(
				new HibernateCallback() {
					// Implement the method required by the interface.
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						List result = session.createQuery(hql).setFirstResult(
								offSet)
								.setMaxResults(10)//TODO 分页的每页记录个数  添加到配置或静态变量
								.list();
						return result;
					}
				});
		return (List<T>) list;
	}

	public <T> Integer getTotalNum(Class<T> entityClass) {
		List list = this.getHibernateTemplate().find(
				"from " + entityClass.getName());
		return list.size();
	}

	public <T> List<T> findByPage(final String hql, final int offSet,
			final int pageSize) {
		// Do the query using HibernateCallback.
		List list = this.getHibernateTemplate().executeFind(
				new HibernateCallback() {
					// Implement the method required by the interface.
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						List result = session.createQuery(hql).setFirstResult(
								offSet).setMaxResults(pageSize).list();
						return result;
					}
				});
		return (List<T>) list;
	}

	public <T> long getTotalNum(final String hql) {
		List list = this.getHibernateTemplate().executeFind(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						List result = session.createQuery(hql).list();
						return result;
					}
				});
		return list.size();
	}

	public <T> long getTotalNum(final String hql, final Object param) {
		List list = this.getHibernateTemplate().executeFind(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						List result = session.createQuery(hql).setParameter(0,
								param).list();
						return result;
					}
				});
		return list.size();
	}
	
	public <T> List<T> findByPage(final String hql, final Object param,
			final int offSet, final int pageSize) {
		List list = this.getHibernateTemplate().executeFind(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						List result = session.createQuery(hql).setParameter(0,
								param).setFirstResult(offSet).setMaxResults(
								pageSize).list();
						return result;
					}
				});
		return (List<T>) list;
	}

	public <T> List<T> findByPage(final String hql, final Object[] params,
			final int offSet, final int pageSize) {
		List list = this.getHibernateTemplate().executeFind(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query query = session.createQuery(hql);
						for (int i = 0; i < params.length; i++) {
							query.setParameter(i, params[i]);
						}
						List result = query.setFirstResult(offSet)
								.setMaxResults(pageSize).list();
						return result;
					}
				});
		return (List<T>) list;
	}
	
	public <T> long getTotalNum(final String hql, final Object[] params) {
		List list = this.getHibernateTemplate().executeFind(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query query = session.createQuery(hql);
						for (int i = 0; i < params.length; i++) {
							query.setParameter(i, params[i]);
						}
						List result = query.list();
						return result;
					}
				});
		return list.size();
	}
	
	public <T> List<T> findObjectByHQLPage(final String hql, final Class<T> entityClass, final Object[] params,  
			final int offSet, final int pageSize) {
		List list = this.getHibernateTemplate().executeFind(
				new HibernateCallback() {
					// Implement the method required by the interface.
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query query = session.createQuery(hql).
								setResultTransformer(Transformers.aliasToBean(entityClass));
						for (int i = 0; i < params.length; i++) {
							query.setParameter(i, params[i]);
						}
						List result = query.setFirstResult(offSet)
								.setMaxResults(pageSize).list();
						return result;
					}
				});
		return (List<T>) list;
	}
	
	public <T> long findObjectByHQLTotalNum(final String hql, final Class<T> entityClass, final Object[] params) {
		List list = this.getHibernateTemplate().executeFind(
				new HibernateCallback() {
					// Implement the method required by the interface.
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query query = session.createQuery(hql).
								setResultTransformer(Transformers.aliasToBean(entityClass));
						for (int i = 0; i < params.length; i++) {
							query.setParameter(i, params[i]);
						}
						List result = query.list();
						return result;
					}
				});
		return list.size();
	}
	
	public <T> List<T> findObjectBySQLPage(final String sql, final Class<T> entityClass, final Object[] params, 
			final int offSet, final int pageSize) {
		List list = this.getHibernateTemplate().executeFind(
				new HibernateCallback() {
					// Implement the method required by the interface.
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query query = session.createSQLQuery(sql).
								setResultTransformer(Transformers.aliasToBean(entityClass));
						for (int i = 0; i < params.length; i++) {
							query.setParameter(i, params[i]);
						}
						List result = query.setFirstResult(offSet)
								.setMaxResults(pageSize).list();
						return result;
					}
				});
		return (List<T>) list;
	}
	
	public <T> List<T> findBySQLPage(final String sql, final Object[] params, 
			final int offSet, final int pageSize) {
		List list = this.getHibernateTemplate().executeFind(
				new HibernateCallback() {
					// Implement the method required by the interface.
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query query = session.createSQLQuery(sql);
						for (int i = 0; i < params.length; i++) {
							query.setParameter(i, params[i]);
						}
						List result = query.setFirstResult(offSet)
								.setMaxResults(pageSize).list();
						return result;
					}
				});
		return (List<T>) list;
	}
	
	public <T> long findObjectBySQLTotalNum(final String sql, final Class<T> entityClass, final Object[] params) {
		List list = this.getHibernateTemplate().executeFind(
				new HibernateCallback() {
					// Implement the method required by the interface.
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query query = session.createSQLQuery(sql).
								setResultTransformer(Transformers.aliasToBean(entityClass));
						for (int i = 0; i < params.length; i++) {
							query.setParameter(i, params[i]);
						}
						List result = query.list();
						return result;
					}
				});
		return list.size();
	}
	
	public void flushClearSession(int newCount, int n){
		if(newCount % n == 0){
			this.getSession().flush();
			this.getSession().clear();
		}		
	}
	
	public void flushClearSession(){
		this.getSession().flush();
		this.getSession().clear();
	}
}
